iT邦幫忙

2024 iThome 鐵人賽

DAY 7
0
自我挑戰組

React 開發者的 TypeScript 探索之旅系列 第 7

【 Day 07 】Custom Types & Interface

  • 分享至 

  • xImage
  •  

Custom Types

根據上一篇的程式碼,雖然我們達成了指定函式型別的目的,但你會發現它在閱讀性上並不是很好:

function calculate(a: number, b: number, fn: (a: number, b: number) => number) {
  return fn(a, b)
}

自定義型別可以提高代碼的可讀性和重用性,尤其是在多處使用相同型別的情況下。我們可以通過將型別提取出來的方式,讓代碼更簡潔、更具結構。例如,我們可以將函式的型別定義提取出來:

type AddFn = (a: number, b: number) => number

然後在需要這個型別的地方放入:

type AddFn = (a: number, b: number) => number

function add(a: number, b: number) {
  const sum = a + b
  return sum
}

function calculate(a: number, b: number, fn: AddFn) {
  return fn(a, b)
}

calculate(1, 2, add) // 3

自定義型別也可以用在我們先前的物件例子上。
原本程式碼如下:

let user: {
  name: string
  age: number
  password: string | number
  isAdmin: boolean
}

提取後的程式碼如下:

type User = {
  name: string
  age: number
  password: string | number
  isAdmin: boolean
}

let user: User

我們也可以將自定義型別與 Union 結合使用,這樣能夠讓變數接受多種型別的值,提升靈活性。例如:

type Password = string | number

在 TypeScript 中,為函式或物件等定義自定義型別( Custom Types )時,通常會以大寫字母開頭。這樣做的主要原因是遵循命名慣例,以便和變數名稱區分開來,並且提高可讀性


interface

Interface 是另一種常用的方式,用來為物件定義型別。它的語法與自定義型別 type 有些不同,主要是 Interface 不需要等號來進行定義。Interface 在 TypeScript 中主要用於物件型別定義:

interface User {
  name: string
  age: number
  password: string | number
  isAdmin: boolean
}

let user: User

並且可以通過繼承來擴展型別的結構,這邊我們以與建構子 ( constructor ) 的搭配使用為範例:

interface User  {
  name: string
  age: number
  password: string | number
  isAdmin: boolean
}
class UserDetails implements User{
  name: string
  age: number
  password: string | number
  isAdmin: boolean
}

在這樣的情形下,建構子不但繼承了 User 的型別,也能夠加入額外的型別,像是下方例子中的 phoneNumber

interface User  {
  name: string
  age: number
  password: string | number
  isAdmin: boolean
}

class UserDetails implements User{
  name: string
  age: number
  password: string | number
  isAdmin: boolean
  phoneNumber: number
}

Interface 的一大優勢在於它可以通過繼承來擴展型別。我們可以使用 interface 繼承現有的型別,並在此基礎上添加新的屬性。這不僅減少了重複代碼,還使得代碼更加易於維護和擴展。

interface User  {
  name: string
  age: number
  password: string | number
  isAdmin: boolean
}

interface User {
  address: string
}

class UserDetails implements User{
  name: string
  age: number
  password: string | number
  isAdmin: boolean
  phoneNumber: number
}

從下面的截圖可以看出,目前報錯的原因顯示為在 UserDetails 中找不到 address 這個屬性,從這個報錯可以得知,我們第二次定義的 interface 是有順利擴充的:

https://ithelp.ithome.com.tw/upload/images/20240917/201690253USqfIhskn.png


Custom Types vs Interface

Custom Types (type) 可以用於多種情境,例如函式、物件型別和 Union。相比之下,Interface 主要用於定義物件型別,並且無法像 type 那樣直接用來定義 Union 型別。雖然 Interface 在一些使用上有一定的限制,但它在物件型別的繼承與擴展上非常有優勢。

在物件型別的繼承和擴展上,Interface 表現得更加靈活。它不僅可以讓我們透過繼承避免代碼重複,還可以在大型專案中,隨著需求變更,輕鬆擴充型別。這種特性在多人協作時尤其有用。

開發者可以基於已有的 Interface 進行擴充,而不會影響現有的代碼,這樣可以保持系統的靈活性和可維護性。

綜合來看,typeInterface 都是強大且靈活的型別管理工具。當你需要定義聯合型別(Union)或函式型別時,type 會是更合適的選擇;而當你需要擴展物件型別並且希望代碼具有可擴充性時,Interface 則提供了更好的靈活性。


上一篇
【 Day 06 】Function
下一篇
【 Day 08 】合併型別與 Literal Types
系列文
React 開發者的 TypeScript 探索之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言